

package net.seqalign;


import java.util.*;

import net.prot.*;

public class AlignmentEvolver {

    List<AlignmentSolution> solutions;

    public AlignmentEvolver(){
	// Load the algorthm data.
	// Turn the string sequences into objects that are useful.
	List<StringBuilder> seqs = new ArrayList<StringBuilder>();
	for (String s : Align.sequences){
	    seqs.add(new StringBuilder(s));
	}
	System.out.println(" #\n #   Aligning these sequences:");
	for (StringBuilder s : seqs){
	    System.out.println(" #    " + s);
	}
	// Generate the initial pop
	solutions = new ArrayList<AlignmentSolution>();
	for (int i = 0; i < Align.popSize; i++){
	    solutions.add(new AlignmentSolution(seqs));
	}
	System.out.println(" # Start fitness: " + solutions.get(0).fitness());
	
    }

    /**
     * Run the evolutionary algorithm.
     */
    public void simulate(){
	System.out.println(" #\n # Running simulation...");
	
	for (int i = 0; i < Align.generations; i++){
	    runGeneration();
	    //System.out.println(" # Generation done: " + (i+1));
	    if (i % 10 == 0) {
		System.out.println(" # Generation " + i + " done.");
	    }
	}
	System.out.println(" # Done.");
	System.out.println("Aligned Sequences:");
	printLinedSequences();
    }

    private void runGeneration(){
	//System.out.println("Generating offspring.");
	List<AlignmentSolution> offspring = generateOffspring();
	/* Now make a new population based on fitnesses. */
	ArrayList<AlignmentSolution> tmp = new ArrayList<AlignmentSolution>();
	//System.out.println("Generating tmp list: put in the old ones.");
	for (AlignmentSolution s : solutions){
	    tmp.add(s);
	}
	//System.out.println("Generating tmp list: put in the children.");
	for (AlignmentSolution s : offspring){
	    tmp.add(s);
	}
	int swaps = (int) (Math.log(Align.popSize) * tmp.size() / 2);
	//System.out.println(" #  swaps=" + swaps);
	//System.out.println(" #  tmp.size()=" + tmp.size());
	//System.out.println(" #  solutions.size()=" + solutions.size());
	//System.out.println(" #   Running swaps...");
	for (int i = 0; i < swaps; i++){
	    int sol1 = (int) (Math.random() * tmp.size());
	    int sol2 = -1;
	    while (sol1 > sol2){
		sol2 = (int) (Math.random() * tmp.size());
	    }
	    /* sol1 is garanteed to be larger than sol2. */
	    AlignmentSolution tmps1 = tmp.get(sol1);
	    AlignmentSolution tmps2 = tmp.get(sol2);
	    //System.out.println(" #   Swap indecies: " + sol1 + ":" + sol2);
	    if (tmps1.fitness() > tmps2.fitness()){
	    //if (10 > 20){
		/* Replace 1 with 2 */
		//System.out.println("Swaping...");
		tmp.set(sol1, tmps2);
		tmp.set(sol2, tmps1);
		//System.out.println("Done Swaping.");
	    } /* else if (tmps1.fitness() >= tmps2.fitness) do nothing; */
	    //System.out.println(" #      Swap done.");
	}
	//System.out.println("Making new solutions array...");
	for (int i = 0; i < Align.popSize; i++){
	    solutions.set(i, tmp.get(i));
	}
    }

    private List<AlignmentSolution> generateOffspring(){
	List<AlignmentSolution> offspring = new ArrayList<AlignmentSolution>();
	for (int i = 0; i < Align.offspringSize; i++){
	    int parent = (int) (Math.random() * Align.popSize);
	    //System.out.println(" > Generating an offsping from parent:" + 
			       //parent);
	    offspring.add(solutions.get(parent).mutate(Align.temp));
	}
	return offspring;
    }

    public void printLinedSequences(){
	AlignmentSolution best = solutions.get(0);
	best.deleteSharedGaps();
	double bestFitness = best.fitness();
	for (AlignmentSolution s : solutions){
	    if (s.fitness() < bestFitness){
		bestFitness = s.fitness();
		best = s;
	    }
	}

	int counter = 0;
	while (true){
	    boolean done = true;
	    for (StringBuilder s : best.sequences){
		int max = ((counter+1) * 80) < s.length() ? 
		    ((counter+1) * 80) : s.length();
		System.out.println("max=" + max + "  start=" + (counter * 80));
		System.out.println(s.substring(counter * 80, max));
		if (s.length() > (counter+1) * 80) done = false;
	    }
	    if (done) break;
	    System.out.println();
	    counter++;
	}
	System.out.println("Fitness: " + best.fitness());
    }
    

}
